package com.exp.bookhouse.security;

/**
 * @Auther L_geng
 * @Date 2020/12/17
 */

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * 认证和授权处理类
 */
@Configuration
public class SecurityConfigurerAdapter extends WebSecurityConfigurerAdapter{
    //依赖注入通用的用户服务类
    @Autowired
    private SecurityService securityService;
    //依赖注入加密接口
    @Autowired
    private PasswordEncoder passwordEncoder;
    //依赖注入用户认证接口
    @Autowired
    private AuthenticationProvider authenticationProvider;
    //依赖注入认证处理成功类，验证用户成功后处理不同用户跳转到不同的页面
    @Autowired
    private AuthenticationSuccessHandler authenticationSuccessHandler;
    /**
     * BCryptPasswordEncoder是PasswordEncoder的接口实现
     * 实现加密功能
     */
    @Bean
    public PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder(); }
    /**
     * DaoAuthenticationProvider是AuthenticationProvider的实现
     */
    @Bean
    public AuthenticationProvider authenticationProvider(){
        DaoAuthenticationProvider provide = new DaoAuthenticationProvider();

        //不隐藏用户未找到异常
        provide.setHideUserNotFoundExceptions(false);
        //设置自定义认证方式，用户登录认证
        provide.setUserDetailsService(securityService);
        //设置密码加密程序认证
        provide.setPasswordEncoder(passwordEncoder);
        return provide;
    }
    //security跨域问题
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new      UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }

    /**
     * 用户认证
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth)throws Exception{
        auth.authenticationProvider(authenticationProvider);
    }
    /**
     * 请求授权
     * 用户授权操作
     */
    @Override
    protected void configure(HttpSecurity http) throws  Exception{
               //跨域问题
        http.cors().and().csrf().disable().authorizeRequests()
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()//跨域问题
            //首页、登录功能、以及静态资源等过滤掉，即可任意访问
                .antMatchers("/static/**","/admin/check","/admin/login",
                        "/book/**","/category/**","/order/**","/cart/**","/user/decodeUser","/admin/loginFail",
//                        "/admin/toRegister","/admin/register",
                        "/swagger-ui.html","/swagger/**","/webjars/**",
                        "/swagger-resources/**","/v2/**").permitAll()
                //这里默认追加ROLE_，/user/**是控制器的请求匹配路径
                .antMatchers("/user/**").hasRole("USER")
                .antMatchers("/admin/**").hasRole("ADMIN")
            //其他所有请求登录后才能访问
            .anyRequest().authenticated()
            .and()
            //将输入的用户名与密码和授权的进行比较
            .formLogin()
                //登录页面，url为controller中的mapping值
                .loginPage("/admin/login").successHandler(authenticationSuccessHandler)
                .usernameParameter("username").passwordParameter("password")
                //登陆失败，返回登陆页面
                .failureUrl("/admin/loginFail")
            .and()
            //注销行为可以任意访问
            .logout()
                .logoutUrl("/admin/logout")//注销页面
                .logoutSuccessUrl("/admin/login").permitAll()//注销成功后返回的页面
        .and()
            //异常处理页面
            .exceptionHandling().accessDeniedPage("/error500Page");
    }

}
